#include "Driver_Usart1.h"

void Driver_USART1_Init(void)
{
    /*1.打开USART1 相关时钟 AFIO 主要控制事件和外部中断 */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
    /*2.配置使用到的引脚模式 ->PA9 TX 复用推挽输出 1011   PA10 RX 浮空输入0100*/
    GPIOA->CRH |= (GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9);
    GPIOA->CRH &= ~GPIO_CRH_CNF9_0;

    GPIOA->CRH |= GPIO_CRH_CNF10_0;
    GPIOA->CRH &= ~(GPIO_CRH_CNF10_1 | GPIO_CRH_MODE10);
    /*3.配置USART1*/
    // 3.1配置波特率
    USART1->BRR = 0X0271;
    // 3.2数据长度  奇偶校验位 停止位
    USART1->CR1 &= ~USART_CR1_M;
    USART1->CR1 &= ~USART_CR1_PCE;
    USART1->CR2 & ~USART_CR2_STOP;
    // 3.3打开使能开关
    // 发送使能
    USART1->CR1 |= USART_CR1_TE;
    // 接收使能
    USART1->CR1 |= USART_CR1_RE;
    // 4.打开中断
    // 4.1打开RXNEIE中断 和IDLEIE
    USART1->CR1 |= USART_CR1_RXNEIE;
    USART1->CR1 |= USART_CR1_IDLEIE;
    //  5.NVIC配置
    // 整个USART1公用一个中断向量
    // 只使用抢占优先级
    NVIC_SetPriorityGrouping(3);

    NVIC_SetPriority(USART1_IRQn, 3);

    NVIC_EnableIRQ(USART1_IRQn);
    //  总开关 放在配置最后
    USART1->CR1 |= USART_CR1_UE;
}

void Driver_USART1_SendChar(uint8_t ch)
{
    // 往DR寄存器直接写   发送数据
    // 等上一个字节发送完成 才能继续发送下一个字节
    // SR_TXE 如果数据正在发送  0   否则1
    while ((USART1->SR & USART_SR_TXE) == 0)
        ;
    USART1->DR = ch;
}

uint8_t Driver_USART1_ReceiveChar(void)
{
    // 接收数据  需要挂起等待接收完一个字节再接收下一个字节
    // SR_RXNE 有数据进来 1
    //         读取一次后 0
    while ((USART1->SR & USART_SR_RXNE) == 0)
        ;

    return USART1->DR;
}

// 发送多个字节
void Driver_USART1_SendString(uint8_t *str, uint8_t len)
{
    for (uint8_t i = 0; i < len; i++)
    {
        Driver_USART1_SendChar(str[i]);
    }
}

// 接收多个字节  推荐buff足够大
// 收到空闲位结束
// buff[]存接收的数据

void Driver_USART1_ReceiveString(uint8_t buff[], uint8_t *len)
{
    uint8_t i = 0;
    while (1)
    {
        if (USART1->SR & USART_SR_RXNE)
        {
            buff[i] = USART1->DR;
            i++;
        }
        if (USART1->SR & USART_SR_IDLE)
        {
            *len = i;
            break;
        }
    }
}

uint8_t buff[100] = {0};
uint8_t len = 0;
void USART1_IRQHandler(void)
{
    // 判断当前那个总中断被触发
    // SR_RXEN是收到一个字节的中断标志位

    if (USART1->SR & USART_SR_RXNE)
    {
        // 对DR的读操作可以直接将该位清理
        // 将数据存到buff
        buff[len] = USART1->DR;
        len++;
    }
    // SR_IDLE是全部发送完成的中断标志位
    else if (USART1->SR & USART_SR_IDLE)
    {
        // 清除中断标志位  又软件序列清除该位 先读USART_SR然后读DR
        USART1->SR;
        USART1->DR;
        // 发出buff
        Driver_USART1_SendString(buff, len);
        len = 0;
    }
}
